#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>      
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <sys/wait.h>
#include <assert.h>

#define NUM 1024
#define NON_REDIR 0     //无重定向
#define INPUT_REDIR 1       //输入重定向 '<'
#define OUT_REDIR 2        //输出重定向 '>'
#define APPEND_REDIR 3      //追加重定向 '>>'



char command[NUM];      //c99数组
char* myargv[64];       //存储指令参数
char* file_name=NULL;
int redir_type=0;

void command_check(char* command)
{
    assert(command);

    //首、尾指针
    char* begin = command;
    char* end = command+strlen(command);
    
    while(begin < end)
    {
        if(*begin == '>')
        {
            *begin=0;
            begin++;
            if(*begin == '>')
            {
                redir_type=APPEND_REDIR;
                begin++;
            }
            else redir_type=OUT_REDIR;
            while(*begin == ' ') begin++;
            file_name=begin;
        }
        else if(*begin == '<')
        {
            *begin=0;       //置0
            redir_type=INPUT_REDIR;
            begin++;
            while(*begin == ' ') begin++;
            file_name = begin;
        }
        else ++begin;
    }

}
int main()
{
    while(1)
    {

        redir_type=NON_REDIR;
        file_name=NULL;

        char buffer[1024]={0};
        getcwd(buffer,sizeof(buffer)-1);        //获取shell的工作路径
        buffer[strlen(buffer)]=0;
        printf("[用户名@主机名 %s]",buffer);
        fflush(stdout);     //刷新缓冲区

        char* s = fgets(command,sizeof(command),stdin);     //输入指令
        command[strlen(command)-1]=0;       //清除 \n 
        

        command_check(command);     //检查指令是否有重定向操作
        myargv[0] = strtok(command," ");
        int i = 1;
        while(myargv[i++] = strtok(NULL," "));      //切割空格

        if(myargv[0] != NULL &&  strcmp(myargv[0],"cd") == 0)
        {
           if(myargv[1] != NULL) chdir(myargv[1]);      //cd命令移动shell的工作路径
           continue;
        }

        pid_t id = fork();
        if(id == 0)
        {

            switch(redir_type)      //使用switch语句
            {
                case NON_REDIR:     //不作处理
                    break;
                case INPUT_REDIR:       //输入重定向
                    {
                        int fd = open(file_name,O_RDONLY);
                        if(fd < 0)
                        {
                            perror("open:");
                            exit(1);
                        }
                        dup2(fd,0);
                    }
                    break;

                case OUT_REDIR:
                case APPEND_REDIR:
                    {
                        umask(0);
                       int flag = O_WRONLY | O_CREAT;
                       if(redir_type == APPEND_REDIR) flag |= O_APPEND;
                       else flag |= O_TRUNC;
                       int fd = open(file_name,flag,0666);
                       if(fd < 0)
                       {
                           perror("open:");
                           exit(1);
                       }
                       dup2(fd,1);
                    }
                    break;
                default:
                    break;
            }
           execvp(myargv[0],myargv);        //进程替换
           exit(1);
        }
        waitpid(id,NULL,0);
    }
    return 0;
}
